#include "gcpch.h"
#include "msgmask.h"
#include <intrin.h>

bool geek_msgmask_create(geek_msgmask *msgmask)
{
    memset(msgmask,0,sizeof(geek_msgmask));

    msgmask->evt = CreateEvent(NULL,FALSE,FALSE,NULL);
    return msgmask->evt != NULL;
}

void geek_msgmask_destroy(geek_msgmask *msgmask)
{
    if(msgmask->evt != NULL)
    {
        CloseHandle(msgmask->evt);
    }

    memset(msgmask,0,sizeof(geek_msgmask));
}

bool geek_msgmask_send(geek_msgmask *msgmask, LONG messages)
{
    if(msgmask->evt != NULL && messages != 0)
    {
        _InterlockedOr(&msgmask->mask,messages);
        return SetEvent(msgmask->evt) != 0;
    }
    else
    {
        return false;
    }
}

static LONG msgmask_extract(volatile LONG *mask)
{
    for(int i = 0; i < sizeof(LONG)*8; ++i)
    {
        LONG bitmask = (LONG)1 << i;
        LONG bit = _InterlockedAnd(mask,~bitmask);
        if((bit&bitmask) != 0)
        {
            return bitmask;
        }
    }

    return 0;
}

bool geek_msgmask_recv(geek_msgmask *msgmask, LONG *message)
{
    while(msgmask->mask == 0)
    {
        DWORD res = WaitForSingleObject(msgmask->evt,INFINITE);
        if(res != WAIT_OBJECT_0)
        {
            return false;
        }
    }

    *message = msgmask_extract(&msgmask->mask);
    return *message != 0;
}

bool geek_msgmask_peek(geek_msgmask *msgmask, LONG *message)
{
    if(msgmask->mask != 0)
    {
        *message = msgmask_extract(&msgmask->mask);
    }
    else
    {
        *message = 0;
    }

    return true;
}
